/*
 * Copyright 2014-2021 UME Framework, GNU General Public License
 */
package com.u2framework.lib.tool.gen.base.type;

import java.util.HashMap;
import java.util.Map;

import com.u2framework.lib.core.util.StringUtil;
import com.u2framework.lib.tool.gen.entity.bean.FieldDescBean;

/**
 * TypeMapper
 *
 * @author SultansOfSwing & MaYue
 */
public class TypeMapper {
    /**
     * DatabaseType Mysql
     */
    private final static String DATABASE_TYPE_MYSQL = "MYSQL";
    /**
     * DatabaseType Oracle
     */
    private final static String DATABASE_TYPE_ORACLE = "ORACLE";
    /**
     * DatabaseType Postgres
     */
    private final static String DATABASE_TYPE_POSTGRES = "POSTGRES";

    /**
     * BizType
     */
    protected String bizType2JavaType(String bizType) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("文本", "String");
        map.put("定长文本", "String");
        map.put("长文本", "String");
        map.put("多语言文本", "String");
        map.put("多语言定长文本", "String");
        map.put("大整数", "java.math.BigInteger");
        map.put("整数", "Integer");
        map.put("三字节整数", "Integer");
        map.put("双字节整数", "Integer");
        map.put("单字节整数", "Byte");
        map.put("长整数", "Long");
        map.put("短整数", "Short");
        map.put("大数值", "java.math.BigDecimal");
        map.put("数值", "java.math.BigDecimal");
        map.put("浮点数", "Float");
        map.put("双精度浮点数", "Double");
        map.put("日期", "java.sql.Date");
        map.put("时间", "java.sql.Time");
        map.put("时间戳", "java.sql.Timestamp");
        map.put("日期时间", "java.sql.Timestamp");
        map.put("二进制大对象", "byte[]");
        map.put("字符大对象", "String");
        map.put("文本大对象", "String");
        map.put("布尔值", "Boolean");
        return map.get(bizType);
    }

    /**
     * bizType2DbType
     *
     * @param bizType
     * @param databaseType
     * @return
     */
    protected String bizType2DbType(String bizType, String databaseType) {
        Map<String, String> map = new HashMap<String, String>();
        if (databaseType.equalsIgnoreCase(DATABASE_TYPE_ORACLE)) {
            map.put("定长文本", "CHAR");
            map.put("多语言定长文本", "NCHAR");
            map.put("文本", "VARCHAR2");
            map.put("多语言文本", "NVARCHAR2");
            map.put("时间", "DATE");
            map.put("日期", "DATE");
            map.put("时间戳", "TIMESTAMP");
            map.put("日期时间", "TIMESTAMP");
            map.put("长文本", "CLOB");
            map.put("大整数", "NUMBER");
            map.put("整数", "NUMBER");
            map.put("三字节整数", "NUMBER");
            map.put("双字节整数", "NUMBER");
            map.put("单字节整数", "NUMBER");
            map.put("长整数", "NUMBER");
            map.put("短整数", "NUMBER");
            map.put("大数值", "NUMBER");
            map.put("数值", "NUMBER");
            map.put("浮点数", "NUMBER");
            map.put("双精度浮点数", "NUMBER");
            map.put("布尔值", "NUMBER");
            map.put("字符大对象", "CLOB");
            map.put("二进制大对象", "BLOB");
        } else if (databaseType.toUpperCase().startsWith(DATABASE_TYPE_POSTGRES)) {
            map.put("日期", "date");
            map.put("时间", "time");
            map.put("时间戳", "timestamp");
            map.put("日期时间", "timestamp");
            map.put("定长文本", "char");
            map.put("多语言定长文本", "char");
            map.put("二进制大对象", "blob");
            map.put("文本", "varchar");
            map.put("多语言文本", "varchar");
            map.put("长文本", "text");
            map.put("字符大对象", "text");
            map.put("长整数", "bigint");
            map.put("大整数", "bigint");
            map.put("三字节整数", "bigint");
            map.put("整数", "integer");
            map.put("双字节整数", "smallint");
            map.put("单字节整数", "smallint");
            map.put("短整数", "smallint");
            map.put("大数值", "decimal");
            map.put("数值", "decimal");
            map.put("浮点数", "decimal");
            map.put("双精度浮点数", "decimal");
            map.put("布尔值", "boolean");
        } else if (databaseType.equalsIgnoreCase(DATABASE_TYPE_MYSQL)) {
            map.put("日期", "date");
            map.put("时间", "time");
            map.put("时间戳", "timestamp");
            map.put("日期时间", "datetime");
            map.put("定长文本", "char");
            map.put("多语言定长文本", "nchar");
            map.put("二进制大对象", "blob");
            map.put("文本", "varchar");
            map.put("多语言文本", "nvarchar");
            map.put("长文本", "longtext");
            map.put("大整数", "bigint");
            map.put("整数", "int");
            map.put("长整数", "int");
            map.put("三字节整数", "mediumint");
            map.put("双字节整数", "smallint");
            map.put("单字节整数", "tinyint");
            map.put("布尔值", "tinyint");
            map.put("短整数", "short");
            map.put("大数值", "decimal");
            map.put("数值", "decimal");
            map.put("浮点数", "float");
            map.put("双精度浮点数", "double");
            map.put("字符大对象", "longtext");
        }
        return map.get(bizType);
    }

    /**
     * bizType2JdbcType
     *
     * @param bizType
     * @param databaseType
     * @return
     */
    protected String bizType2JdbcType(String bizType, String databaseType) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("文本", "VARCHAR");
        map.put("定长文本", "CHAR");
        map.put("长文本", "LONGVARCHAR");
        map.put("多语言文本", "VARCHAR");
        map.put("多语言定长文本", "CHAR");

        if (DATABASE_TYPE_ORACLE.equalsIgnoreCase(databaseType)) {
            map.put("大整数", "DECIMAL");
            map.put("整数", "DECIMAL");
            map.put("三字节整数", "DECIMAL");
            map.put("双字节整数", "DECIMAL");
            map.put("单字节整数", "DECIMAL");
            map.put("长整数", "DECIMAL");
            map.put("短整数", "DECIMAL");
        } else {
            map.put("大整数", "BIGINT");
            map.put("整数", "INTEGER");
            map.put("三字节整数", "MEDIUMINT");
            map.put("双字节整数", "SMALLINT");
            map.put("单字节整数", "TINYINT");
            map.put("长整数", "BIGINT");
            map.put("短整数", "SMALLINT");
        }
        map.put("大数值", "DECIMAL");
        map.put("数值", "DECIMAL");
        map.put("浮点数", "DECIMAL");
        map.put("双精度浮点数", "DECIMAL");
        map.put("日期", "DATE");
        map.put("时间", "TIME");
        map.put("时间戳", "TIMESTAMP");
        map.put("日期时间", "TIMESTAMP");
        map.put("二进制大对象", "BLOB");
        map.put("字符大对象", "CLOB");
        map.put("文本大对象", "CLOB");
        map.put("布尔值", "BOOLEAN");
        return map.get(bizType);
    }

    /**
     * dbType2BizType
     * 
     * @param dbType
     * @return
     */
    protected String dbType2BizType(String dbType) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("CHAR", "定长文本");
        map.put("NVARCHAR", "文本");
        map.put("VARCHAR", "文本");
        map.put("VARCHAR2", "文本");
        map.put("NVARCHAR2", "文本");
        map.put("TIMESTAMP", "时间戳");
        map.put("BIGINT", "大整数");
        map.put("INT", "整数");
        map.put("INTEGER", "整数");
        map.put("MEDIUMINT", "三字节整数");
        map.put("SMALLINT", "双字节整数");
        map.put("TINYINT", "单字节整数");
        //map.put("LONG", "长整数");
        map.put("SHORT", "短整数");
        map.put("DECIMAL", "数值");
        map.put("NUMBER", "数值");
        map.put("DATE", "日期");
        map.put("TIME", "时间");
        map.put("DATETIME", "日期时间");
        map.put("LONGTEXT", "长文本");
        map.put("TEXT", "长文本");
        map.put("BLOB", "二进制大对象");
        map.put("CLOB", "字符大对象");
        map.put("MEDIUMBLOB", "二进制大对象");
        map.put("BOOLEAN", "布尔值");

        return map.get(dbType);
    }

    /**
     * checkPhysicalDbDataType
     *
     * @param dataType
     * @param databaseType
     * @return
     */
    protected boolean checkPhysicalDbDataType(String dataType, String databaseType) {
        if (DATABASE_TYPE_ORACLE.equalsIgnoreCase(databaseType)) {
            return true;
        } else if (DATABASE_TYPE_MYSQL.equalsIgnoreCase(databaseType)) {
            return true;
        } else {
            return true;
        }
    }

    /**
     * checkDataType
     *
     * @param bizType
     * @return
     */
    public boolean checkDataType(String bizType, String dataTypeWithLength, String databaseType) {
        boolean result = true;
        if (StringUtil.isNotEmpty(dataTypeWithLength)) {
            String typePart = dataTypeWithLength.trim();
            typePart = typePart.contains("(") ? typePart = typePart.substring(0, typePart.indexOf("(")) : typePart;
            result = checkPhysicalDbDataType(dataTypeWithLength, databaseType);
        }
        if (result && bizType2JavaType(bizType) == null) {
            result = false;
        }
        return result;
    }

    /**
     * getJavaType
     * 
     * @param bizType
     * @param fieldDescBean
     * @param databaseType
     * @return
     */
    public String getJavaType(String bizType, FieldDescBean fieldDescBean, String databaseType) {
        String javaType = bizType2JavaType(bizType);

        if (javaType == null) {
            throw new RuntimeException("No found available Java type for [" + bizType + "] ," + fieldDescBean.getColId() + ", " + fieldDescBean.getColName());
        }
        return javaType;
    }

    /**
     * getDBDataType
     *
     * @param bizType
     * @param fieldDescBean
     * @return
     */
    public String getDbDataType(final String bizType, FieldDescBean fieldDescBean, String databaseType) {
        String result = this.bizType2DbType(bizType, databaseType);
        if (result == null) {
            throw new RuntimeException("No found available Datatabase type for [" + bizType + "] ," + fieldDescBean.getColId() + ", " + fieldDescBean.getColName());
        }
        return result;
    }

    /**
     * getJdbcType
     *
     * @param bizType
     * @param fieldDescBean
     * @return
     */
    public String getJdbcType(String bizType, FieldDescBean fieldDescBean, String databaseType) {
        String result = bizType2JdbcType(bizType, databaseType);
        if (result == null) {
            throw new RuntimeException("No found available JDBC type for [" + bizType + "] ," + fieldDescBean.getColId() + ", " + fieldDescBean.getColName());
        }
        return result;
    }

    /**
     * getBizTypeFromDbDicType
     *
     * @param dbDicDataType
     * @return
     */
    public String getBizTypeFromDbDicType(String dbDicDataType) {
        dbDicDataType = dbDicDataType.trim().toUpperCase();
        if (dbDicDataType.contains("(")) {
            dbDicDataType = dbDicDataType.substring(0, dbDicDataType.indexOf("("));
        }
        String bizTyoe = dbType2BizType(dbDicDataType);
        return bizTyoe;
    }

}
